home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 7: Sunsite / Linux Cubed Series 7 - Sunsite Vol 1.iso / system / admin / linuxcon.000 / linuxcon / linuxconf-1.6 / userconf / user.c < prev    next >
C/C++ Source or Header  |  1996-07-22  |  18KB  |  744 lines

  1. #include <stdio.h>
  2. #include <string.h>
  3. #include <stdlib.h>
  4. #include <unistd.h>
  5. #include <ctype.h>
  6. #include <pwd.h>
  7. #include <errno.h>
  8. #include <time.h>
  9. #include <sys/stat.h>
  10. #include "internal.h"
  11. #include "userconf.h"
  12. #include "../paths.h"
  13. //#include "../xconf/xconf.h"
  14. #include "userconf.m"
  15.  
  16. static USERCONF_HELP_FILE help_user ("user");
  17. USERCONF_HELP_FILE help_password ("password");
  18.  
  19.  
  20. PRIVATE void USER::init(
  21.     const char *_name,
  22.     const char *_passwd,
  23.     int _uid,
  24.     int _gid,
  25.     const char *_gecos,
  26.     const char *_dir,
  27.     const char *_shell)
  28. {
  29.     name.setfrom (_name);
  30.     passwd.setfrom (_passwd);
  31.     uid = _uid;
  32.     gid = _gid;
  33.     comment.setfrom (_gecos);
  34.     wrkdir.setfrom (_dir);
  35.     shell.setfrom (_shell);
  36.     special = !shells_isok(_shell);
  37. }
  38.  
  39. PUBLIC USER::USER(
  40.     const char *_name,
  41.     const char *_passwd,
  42.     int _uid,
  43.     int _gid,
  44.     const char *_gecos,
  45.     const char *_dir,
  46.     const char *_shell)
  47. {
  48.     init (_name,_passwd,_uid,_gid,_gecos,_dir,_shell);
  49. }
  50.  
  51. PUBLIC USER::USER()
  52. {
  53.     init ("","",-1,-1,"","","");
  54. }
  55. /*
  56.     Decompose a /etc/passwd style line into words
  57. */
  58. int user_splitline (const char *line, char words[9][100])
  59. {
  60.     int nbword = 0;
  61.     char *dst = words[0];
  62.     for (int i=0; i<9; i++) words[i][0] = '\0';
  63.     while (*line != '\0' && *line != '\n'){
  64.         if (*line == ':'){
  65.             line++;
  66.             *dst = '\0';
  67.             nbword++;
  68.             dst = words[nbword];
  69.         }else{
  70.             *dst++ = *line++;
  71.         }
  72.     }
  73.     *dst = '\0';
  74.     return nbword;
  75. }
  76. /*
  77.     Taken from /etc/passwd directly
  78. */
  79. PUBLIC USER::USER(const char *line)
  80. {
  81.     char words[9][100];
  82.     user_splitline (line,words);
  83.     name.setfrom (words[0]);
  84.     passwd.setfrom (words[1]);
  85.     uid = atoi(words[2]);
  86.     gid = atoi(words[3]);
  87.     comment.setfrom (words[4]);
  88.     wrkdir.setfrom (words[5]);
  89.     shell.setfrom (words[6]);
  90.     special = !shells_isok(words[6]);
  91. }
  92. PUBLIC USER::USER(struct passwd *p)
  93. {
  94.     init (p->pw_name,p->pw_passwd,p->pw_uid,p->pw_gid,p->pw_gecos,p->pw_dir
  95.         ,p->pw_shell);
  96. }
  97. PUBLIC USER::~USER()
  98. {
  99. }
  100. /*
  101.     Return the crypt password field
  102. */
  103. PUBLIC const char *USER::getpwd()
  104. {
  105.     return passwd.get();
  106. }
  107.  
  108. /*
  109.     Write one record of /etc/passwd
  110. */
  111. PUBLIC void USER::write(FILE *fout)
  112. {
  113.     fprintf (fout,"%s:%s:%d:%d:%s:%s:%s\n"
  114.         ,name.get(),passwd.get(),uid,gid,comment.get()
  115.         ,wrkdir.get(),shell.get());
  116. }
  117. /*
  118.     Return the login name of the user.
  119. */
  120. PUBLIC const char *USER::getname()
  121. {
  122.     return name.get();
  123. }
  124. /*
  125.     Return the long informative name of the user.
  126. */
  127. PUBLIC const char *USER::getgecos()
  128. {
  129.     return comment.get();
  130. }
  131. /*
  132.     Return the User ID of the user.
  133. */
  134. PUBLIC int USER::getuid()
  135. {
  136.     return uid;
  137. }
  138. /*
  139.     Return the User GID of the user.
  140. */
  141. PUBLIC int USER::getgid()
  142. {
  143.     return gid;
  144. }
  145. /*
  146.     Return the shell (path) of the user.
  147.     If the user has no explicit shell, return the default.
  148. */
  149. PUBLIC const char *USER::getshell()
  150. {
  151.     return shell.is_empty() ? shells_getdefault() : shell.get();
  152. }
  153. /*
  154.     Return != 0 if this user account is a special admin account
  155.     unrelated to any user.
  156. */
  157. PUBLIC int USER::is_admin()
  158. {
  159.     const char *pt = name.get();
  160.     return strcmp(pt,"root")==0
  161.         || strcmp(pt,"adm")==0
  162.         || strcmp(pt,"bin")==0
  163.         || strcmp(pt,"daemon")==0
  164.         || strcmp(pt,"sys")==0
  165.         || strcmp(pt,"postmaster")==0
  166.         || strcmp(pt,"usenet")==0
  167.         || strcmp(pt,"sync")==0;
  168. }
  169. /*
  170.     Return != 0 if this user account is a special non user account
  171.     generally intended for machine to machine connection like uucp.
  172. */
  173. PUBLIC int USER::is_special()
  174. {
  175.     return special;
  176. }
  177. /*
  178.     Check if a user is correctly configured.
  179.     Return -1 if not.
  180. */
  181. PRIVATE int USER::check(
  182.     USERS &users,
  183.     GROUPS &groups,
  184.     int full)    // Check everything, even directory
  185.             // access and so on
  186. {
  187.     char status[1000];
  188.     status[0] = '\0';
  189.     USER *other = users.getitem(name.get());
  190.     if (other != NULL && other != this){
  191.         strcat (status,MSG_U(E_DUPLOGIN,"User already exist (login name)\n"));
  192.     }
  193.     other = users.getfromuid(uid);
  194.     if (other != NULL && other != this){
  195.         strcat (status,MSG_U(E_DUPID,"User already exist (User ID)\n"));
  196.     }
  197.     if (groups.getfromgid(gid)==NULL){
  198.         strcat (status,MSG_U(E_UNKNOWNGRP,"Group do not exist\n"));
  199.     }
  200.     if (!special && !shells_isok(shell.get())){
  201.         strcat (status,MSG_U(E_IVLDSHELL,"Invalid command interpretor\n"));
  202.     }else if (!shells_exist(shell.get())){
  203.         strcat (status,MSG_U(E_NOSHELL,"Command interpretor not available\n"));
  204.     }
  205.     char status_dir[200];
  206.     int code_dir = checkhome(status_dir);
  207.     /* #Specification: userconf / user / home directory
  208.         userconf do not allow a user to have an empty directory
  209.         nor a directory which point to something else than
  210.         a directory.
  211.     */
  212.     if (code_dir != 0 && (full || code_dir != ENOENT)){
  213.         strcat (status,status_dir);
  214.     }
  215.     int ret = 0;
  216.     if (status[0] != '\0'){
  217.         xconf_error ("%s",status);
  218.         ret = -1;
  219.     }
  220.     return ret;
  221. }
  222.  
  223. /*
  224.     Check if the home of the user do exist
  225.     Return    -1        : No home directory specified
  226.             ENOENT    : path does not exist.
  227.             ENOTDIR : path do exist, but is not a directory.
  228.             EPERM    : path do exist but permissions are wrong
  229.             0        : all is ok.
  230. */
  231. PUBLIC int USER::checkhome (
  232.     char *status)    // Will contain an explanation of the problem
  233.                     // if any (may be NULL)
  234. {
  235.     int ret = -1;
  236.     const char *msg = MSG_U(E_NOHOME,"No home directory specified");
  237.     if (!wrkdir.is_empty()){
  238.         struct stat st;
  239.         if (stat(wrkdir.get(),&st)!=-1){
  240.             if (S_ISDIR (st.st_mode)){
  241.                 /* #Specification: user / home directory / owner
  242.                     userconf check that the home directory
  243.                     of a user is own (gid and uid) by him
  244.                     except for special account (
  245.                     administrative, PPP, uucp, etc...)
  246.                     where we generally allocate the same
  247.                     directory to a bunch of users.
  248.                 */
  249.                 if (special
  250.                     || (st.st_uid == uid && st.st_gid == gid)){
  251.                     ret = 0;
  252.                     msg = MSG_U(N_IS_OK,"is ok");
  253.                 }else{
  254.                     ret = EPERM;
  255.                     if (st.st_uid == uid){
  256.                         msg = MSG_U(E_IVLDGRP,"have invalid group");
  257.                     }else if (st.st_gid == gid){
  258.                         msg = MSG_U(E_IVLDOWN,"have invalid owner");
  259.                     }else{
  260.                         msg = MSG_U(E_IVLDG_O,"have invalid owner and group");
  261.                     }
  262.                 }
  263.             }else{
  264.                 ret = ENOTDIR;
  265.                 msg = MSG_U(E_EXISTDIR,"do exist, but is not a directory");
  266.             }
  267.         }else{
  268.             msg = MSG_U(E_DONOTEXIST,"does not exist");
  269.             ret = ENOENT;
  270.         }
  271.     }
  272.     if (status != NULL){
  273.         sprintf (status
  274.             ,MSG_U(E_HOMEUSER,"Home directory of user %s: %s\n%s\n")
  275.             ,name.get(),wrkdir.get(),msg);
  276.     }
  277.     return ret;
  278. }
  279. /*
  280.     Set the name of the new user
  281. */
  282. PUBLIC void USER::setname(const char *_name)
  283. {
  284.     if (_name != NULL) name.setfrom (_name);
  285. }
  286.  
  287. /*
  288.     Create/update the user home directory.
  289.     Return -1 if any error.
  290. */
  291. PUBLIC int USER::sethome ()
  292. {
  293.     char status[200];
  294.     int ret = checkhome(status);
  295.     if (ret != 0){
  296.         if (ret == -1 || ret == ENOTDIR){
  297.             xconf_error ("%s",status);
  298.         }else if (perm_rootaccess(
  299.             MSG_U(P_SETUSERDIR,"set user %s directory\n")
  300.             ,name.get())){
  301.             if (ret == ENOENT){
  302.                 ret = mkdir (wrkdir.get(),0755);
  303.                 if (ret == 0) ret = EPERM;
  304.             }
  305.             if (ret == EPERM){
  306.                 if (chown (wrkdir.get(),uid,gid) != -1){
  307.                     ret = 0;
  308.                 }
  309.             }
  310.             if (ret != 0){
  311.                 xconf_error (
  312.                     MSG_U(E_SETUPDIR
  313.                      ,"Can't setup user %s's home directory %s\n"
  314.                      "reason: %s\n")
  315.                     ,name.get(),wrkdir.get()
  316.                     ,strerror (errno));
  317.             }
  318.         }
  319.     }
  320.     return ret;
  321. }
  322.  
  323. static int user_str2gid(
  324.     GROUPS &groups,
  325.     SSTRING &group)
  326. {
  327.     /* #Specification: user record / gid / format
  328.         GID may be entered either as a string (a group name)
  329.         or as a number.
  330.     */
  331.     const char *str = group.get();
  332.     int gid = groups.getgid(str);
  333.     if (gid == -1 && isdigit(str[0])) gid = atoi(str);
  334.     return gid;
  335. }
  336.  
  337. /*
  338.     Edit the specification of a user.
  339.     Return -1 if the user escape without accepting the changes.
  340.     Return 0 if the user accepted the change
  341.     Return 1 if the user wish to delete this record.
  342. */
  343. PUBLIC int USER::edit(USERS &users, GROUPS &groups, int is_new)
  344. {
  345.     DIALOG dia;
  346.     dia.newf_str (MSG_U(F_LOGIN,"Login name"),name);
  347.     dia.newf_str (MSG_U(F_FULLNAME,"Full name"),comment);
  348.     SSTRING group;
  349.     group.setfrom (gid);
  350.     if (gid == -1){
  351.         group.setfrom (groups.getdefault());
  352.         shell.setfrom (shells_getdefault());
  353.     }else{
  354.         GROUP *grp = groups.getfromgid(gid);
  355.         if (grp != NULL){
  356.             group.setfrom (grp->getname());
  357.         }
  358.     }
  359.     FIELD_COMBO *grpl = dia.newf_combo (MSG_U(F_GROUP,"group"),group);
  360.     {
  361.         groups.sortbyname();
  362.         for (int i=0; i<groups.getnb(); i++){
  363.             grpl->addopt (groups.getitem(i)->getname());
  364.         }
  365.     }
  366.     FIELD *fhome = dia.newf_str (MSG_U(F_HOME,"Home directory(opt)")
  367.         ,wrkdir);
  368.     dia.newf_str (MSG_U(F_SHELL,"Command interpreter(opt)")
  369.         ,shell);
  370.     SSTRING struid;
  371.     if (uid != -1) struid.setfrom (uid);
  372.     FIELD *fuid = dia.newf_str (MSG_U(F_UID,"User ID(opt)"),struid);
  373.     if (is_special()){
  374.         fhome->set_readonly();
  375.         grpl->set_readonly();
  376.         fuid->set_readonly();
  377.     }
  378.     SHADOW *shadow = NULL;
  379.     int add_shadow = 0;
  380.     if (shadow_exist()){
  381.         shadow = users.getshadow(this);
  382.         if (shadow == NULL){
  383.             shadow = new SHADOW;
  384.             shadow->passwd.setfrom (passwd);
  385.             passwd.setfrom ("x");
  386.             add_shadow = 1;
  387.         }
  388.         dia.newf_title ("",MSG_U(T_PASSMNG,"Password management"));
  389.         dia.newf_num (MSG_U(F_PASSMAY,"Must keep # days"),shadow->may);
  390.         dia.newf_num (MSG_U(F_PASSMUST,"Must change after # days"),shadow->must);
  391.         dia.newf_num (MSG_U(F_PASSWARN,"Warn # days before expieration"),shadow->warn);
  392.         dia.newf_num (MSG_U(F_PASSEXPIRE,"Account expire after # days"),shadow->expire);
  393.     }
  394.     int field = 0;
  395.     int ret = -1;
  396.     while (1){
  397.         MENU_STATUS code = dia.edit (
  398.             MSG_U(T_USERINFO,"User information")
  399.             ,MSG_U(I_USERINTRO
  400.              ,"You must specify at least the name\n"
  401.               "and the full name")
  402.             ,help_user.getpath()
  403.             ,field
  404.             ,MENUBUT_ACCEPT|MENUBUT_CANCEL|MENUBUT_DEL);
  405.         if (code == MENU_CANCEL || code == MENU_ESCAPE){
  406.             break;
  407.         }else if (!perm_rootaccess(
  408.             MSG_U(P_USERDATA
  409.                 ,"to maintain the user database"))){
  410.             dia.restore();
  411.         }else if (code == MENU_DEL){
  412.             if (xconf_areyousure(MSG_U(Q_DELUSER
  413.                 ,"Confirm deletion of user account"))){
  414.                 ret = 1;
  415.                 break;
  416.             }
  417.         }else{
  418.             /* #Specification: userconf / user account / semicolon
  419.                 A check is made to ensure that the user
  420.                 has not entered a : in any field
  421.                 during edition.
  422.             */
  423.             if (name.strchr(':') != NULL
  424.                 || comment.strchr(':') != NULL
  425.                 || group.strchr(':') != NULL
  426.                 || struid.strchr(':') != NULL
  427.                 || shell.strchr (':') != NULL
  428.                 || wrkdir.strchr (':') != NULL){
  429.                 xconf_error (MSG_U(E_NO2PT
  430.                     ,"No : in any field allowed"));
  431.             }else{
  432.                 gid = user_str2gid(groups,group);
  433.                 uid = struid.is_empty()
  434.                     ? users.getnewuid(gid)
  435.                     : struid.getval();
  436.                 if (wrkdir.is_empty()){
  437.                     /* #todo: userconf / default home directory
  438.                         We currently force every new user into /home/...
  439.                         unless specified. This should be configurable
  440.                         maybe.
  441.                     */
  442.                     char buf[50];
  443.                     sprintf (buf,"/home/%s",name.get());
  444.                     wrkdir.setfrom (buf);
  445.                 }
  446.                 if (check(users,groups,0)==0){
  447.                     /* #Specification: user edit / bad html dialog
  448.                         This is a good exemple of a bad dialog
  449.                         (or at least complex dialog) for html mode
  450.                         All side effect of the dialog must be done
  451.                         at the exit. The do_sethome kludge is there
  452.                         just for that.
  453.                         Anyway, this dialog is bad and should contain
  454.                         the passwords (2 lines) when creating a new
  455.                         account. Flat dialog are generally nicer.
  456.                     */                    
  457.                     int do_sethome = 0;
  458.                     char status[200];
  459.                     int code = checkhome (status);
  460.                     if (code == ENOTDIR){
  461.                         xconf_error ("%s",status);
  462.                     }else if (code != 0){
  463.                         if (code == ENOENT){
  464.                             strcat (status
  465.                                 ,MSG_U(Q_CREATE,"\nDo you want to create it ?"));
  466.                         }else if (code == EPERM){
  467.                             strcat (status
  468.                                 ,MSG_U(Q_FIXIT,"\nDo you want to fix it ?"));
  469.                         }
  470.                         if (xconf_yesno(
  471.                             MSG_U(Q_USERHOME,"User home directory")
  472.                             ,status,help_nil)==MENU_YES){
  473.                             do_sethome = 1;
  474.                         }
  475.                     }
  476.                     if (checkhome(NULL)==0 || do_sethome){
  477.                         ret = 0;
  478.                         if (is_new) ret = editpass(1,shadow);
  479.                         if (ret == 0){
  480.                             if (do_sethome)    sethome();
  481.                             setmodified();
  482.                             if (shadow != NULL){
  483.                                 shadow->name.setfrom (name);
  484.                                 if (add_shadow) users.addshadow (shadow);
  485.                             }
  486.                         }
  487.                         break;
  488.                     }
  489.                 }
  490.             }
  491.         }
  492.     }
  493.     if (ret != 0){
  494.         dia.restore();
  495.         gid = user_str2gid(groups,group);
  496.         uid = struid.getval();
  497.     }
  498.     return ret;
  499. }
  500. /*
  501.     Check if a password is weak
  502. */
  503. static int pass_isweak(const char *pass)
  504. {
  505.     /* #Specification: userconf / net password / rejected
  506.         New password are validated with some rules to ensure
  507.         they are difficult enough. Here are the rules.
  508.         
  509.         #
  510.         -6 chars minimum
  511.         -Must have at least one non-letter character
  512.         #
  513.     */
  514.     int ret = 1;
  515.     if (pass[0] == '\0' || strcmp(pass,"*")==0){
  516.         /* #Specification: userconf / user password / empty and *
  517.             Only root is allowed to set an empty password or one
  518.             with only * in it.
  519.             It will be refused (error message) for all other
  520.             users.
  521.         */
  522.         if (getuid()==0){
  523.             ret = 0;
  524.         }else{
  525.             xconf_error (
  526.                 MSG_U(E_NULLPASS,"Empty password not allowed.\n"
  527.                 "Only root is allowed to do so.\n"
  528.                 "This is not a good idea though!"));
  529.         }
  530.     }else{
  531.         PASSWD_VALID vl;
  532.         /* #Specification: userconf / password / checking
  533.             userconf check the minimum length and the
  534.             amount of non alpha character in a new password.
  535.  
  536.             If the new password does not fullfill the local
  537.             policies, it is rejected.
  538.         */
  539.         if ((int)strlen(pass)>=vl.minlen){
  540.             int nbalpha = 0;
  541.             while (*pass != '\0'){
  542.                 if (!isalpha(*pass)) nbalpha++;
  543.                 pass++;
  544.             }
  545.             if (nbalpha >= vl.minnonalpha) ret = 0;
  546.         }
  547.         if (ret){
  548.             xconf_error (MSG_U(E_WEAKPASS
  549.                 ,"Password not accepted\n"
  550.                 "Select a more complicated one\n"
  551.                 "The local policies are\n"
  552.                 "\n"
  553.                 "Minimum length : %d\n"
  554.                 "Minimum number of non-alpha character : %d\n")
  555.                 ,vl.minlen,vl.minnonalpha);
  556.         }
  557.     }
  558.     return ret;
  559. }
  560.  
  561. /*
  562.     Update the passwd field with a new password and manage SHADOW
  563. */
  564. PRIVATE void USER::update_passwd (
  565.     const char *newp,
  566.     SHADOW *shadow,
  567.     int is_lock)
  568. {
  569.     SSTRING *pwd = &passwd;
  570.     if (shadow != NULL){
  571.         time_t tim = time(NULL);
  572.         int days = tim/(24*60*60);
  573.         if (is_lock){
  574.             if (shadow->disable == 0){
  575.                 shadow->disable = days;
  576.                 shadow->last = days;
  577.             }
  578.         }else{
  579.             pwd = &shadow->passwd;
  580.             shadow->last = days;
  581.             shadow->disable = 0;
  582.             passwd.setfrom ("x");
  583.         }
  584.     }
  585.     char buf[80];
  586.     char *store = buf;
  587.     strcpy (buf,newp);
  588.     if (buf[0] != '\0' && strcmp(buf,"*")!=0){
  589.         store = crypt(buf,buf);
  590.     }
  591.     pwd->setfrom (store);
  592. }
  593. /*
  594.     Edit(set) the password of a user.
  595.     Return -1 if the user escape without accepting the changes.
  596.     If the user enter the password correctly and accept it, the
  597.     object USER is updated with the crypted version.
  598. */
  599. PUBLIC int USER::editpass(
  600.     int lock_available,    // The dialog allow locking the account
  601.                         // Putting * in the password
  602.                         // or managing the SHADOW record properly
  603.     SHADOW *shadow)
  604. {
  605.     int ret = -1;
  606.     while (1){
  607.         DIALOG dia;
  608.         char is_lock = passwd.cmp("*")==0;
  609.         if (shadow) is_lock = shadow->disable != 0;
  610.         if (lock_available){
  611.             dia.newf_chk ("",is_lock,MSG_U(F_LOCKACCOUNT,"Lock the account"));
  612.         }
  613.         SSTRING buf1;
  614.         dia.newf_pass (MSG_U(F_PASSWORD,"Password"),buf1);
  615.         SSTRING buf2;
  616.         dia.newf_pass (MSG_U(F_CONFIRM,"Confirmation"),buf2);
  617.         char title[80];
  618.         sprintf (title,MSG_U(T_PASSWORD,"%s's password"),name.get());
  619.         if (dia.edit (title
  620.             ,MSG_U(I_PASSINTRO
  621.              ,"You must enter the new password twice\n"
  622.              "To make sure you have enter it\n"
  623.              "correctly.\n")
  624.             ,help_password.getpath()
  625.             ,0) != MENU_ACCEPT){
  626.             break;
  627.         }else if (lock_available && is_lock){
  628.             if (buf1.is_empty() && buf2.is_empty()){
  629.                 update_passwd ("*",shadow,1);
  630.                 setmodified();
  631.                 ret = 0;
  632.                 break;
  633.             }else{
  634.                 xconf_error (MSG_U(E_LOCKORNOT
  635.                     ,"A locked account does not have a password\n"
  636.                      "either you type a password(twice)\n"
  637.                      "either you lock the account and then\n"
  638.                      "you don't enter any passwords"));
  639.                 
  640.             }
  641.         }else if (buf1.cmp(buf2)!=0){
  642.             xconf_error (MSG_U(E_MISMATCH
  643.                 ,"There was a mismatch\n"
  644.                 "Please try again\n"));
  645.         }else if (!pass_isweak(buf1.get())){
  646.             xconf_notice (MSG_U(N_ACCEPT,"New password for user %s accepted")
  647.                 ,name.get());
  648.             update_passwd (buf1.get(),shadow,0);
  649.             setmodified();
  650.             ret = 0;
  651.             break;
  652.         }
  653.     }
  654.     return ret;
  655. }
  656. /*
  657.     Edit the password of the current user.
  658.     Ask for his current password to allow him to continue.
  659. */
  660. PUBLIC int USER::edithispass(SHADOW *shadow)
  661. {
  662.     /* #Specification: userconf / passwd clone
  663.         userconf can be a clone of the /bin/passwd program, If the
  664.         proper symlink is done. When a user attempt to change
  665.         his own password, the program prompt for the current one.
  666.     */
  667.     int ret = -1;
  668.     char buf1[MAX_LEN+1];
  669.     if (xconf_inputpass (
  670.         MSG_U(T_CHGYOURPASS,"Changing your password")
  671.         ,MSG_U(I_ENTERYOURPASS,"Please enter your current password\n")
  672.         ,help_password
  673.         ,buf1)==MENU_ACCEPT){
  674.         if (strcmp(crypt(buf1,passwd.get()),passwd.get())==0){
  675.             ret = editpass(0,shadow);
  676.         }else{
  677.             xconf_error (MSG_R(E_IVLDPASS));
  678.         }
  679.     }
  680.     return ret;
  681. }
  682.  
  683. /*
  684.     non tty oriented passwd changing facility
  685.     copy the functionnality of the old passwd program.
  686. */
  687. PUBLIC int USER::edithispass_notty(SHADOW *shadow)
  688. {
  689.     int ret = -1;
  690.     printf (MSG_U(W_CHGPASS,"Changing password for %s\n"),getname());
  691.     printf (MSG_U(Q_ENTEROLDPASS,"Enter old password:"));
  692.     fflush (stdout);
  693.     char old[100];
  694.     if (fgets (old,sizeof(old)-1,stdin) != NULL){
  695.         printf (MSG_U(Q_ENTERNEWPASS,"Enter new password:"));
  696.         fflush (stdout);
  697.         char newp[100];
  698.         if (fgets (newp,sizeof(newp)-1,stdin) != NULL){
  699.             printf (MSG_U(Q_RETYPE,"Re-type new password:"));
  700.             fflush (stdout);
  701.             char newp2[100];
  702.             if (fgets (newp2,sizeof(newp2)-1,stdin) != NULL){
  703.                 if (strcmp(crypt(old,passwd.get()),passwd.get())!=0){
  704.                 }else if (strcmp(newp,newp2)!=0){
  705.                 }else if (pass_isweak(newp)){
  706.                 }else{
  707.                     update_passwd (newp,shadow,0);
  708.                     ret = 0;
  709.                 }
  710.             }
  711.         }
  712.     }
  713.     return ret;
  714. }
  715.  
  716. #ifdef TEST
  717.  
  718. int main (int argc, char *argv[])
  719. {
  720.     dialog_clear();
  721.     USERS users;
  722.     GROUPS groups;
  723.     if (argc == 1){
  724.         USER *user = new USER;
  725.         if (user->edit(users,groups,1)==0){
  726.             users.add (user);
  727.             users.write();
  728.         }else{
  729.             delete user;
  730.         }
  731.     }else{
  732.         USER *user = users.getitem(argv[1]);
  733.         if (user != NULL && user.edit(users,groups,0)==0){
  734.             users.write();
  735.         }
  736.     }
  737.     return 0;
  738. }
  739.  
  740. #endif
  741.  
  742.  
  743.  
  744.